package com.utsirc;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.app.Application;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;

import com.utsirc.activities.ChannelsFragment;
import com.utsirc.activities.ChatFragment;
import com.utsirc.activities.ConnectActivity;
import com.utsirc.activities.Main;
import com.utsirc.irc.IRCService;
import com.utsirc.irc.IRCServiceConnection;
import com.utsirc.types.Channel;
import com.utsirc.types.ChannelState;
import com.utsirc.types.ChatMessage;
import com.utsirc.types.User;

public class UTSirC extends Application {

	public static UTSirC instance;
	/**
	 * handler, used by the service to talk back to multiple activities update
	 * the UI thread controls the flow of the application based on the state of
	 * the IRC client
	 */
	public Handler messageHandler;

	/**
	 * used for binding service to activity so activities can utilize the
	 * service
	 */
	public IRCServiceConnection myConnection;

	/**
	 * global user object, different from irc user obj
	 */
	public User currentUser;

	public Channel currentChannel;

	// list of channel names
	public List<Channel> channels;

	/**
	 * add channel to the current channel list; ignore if already present
	 * 
	 * @param channelName
	 */
	public void addChannel(String channelName) {

		// see if the channel already exist in list
		boolean channelExist = false;
		for (Channel c : channels) {
			if (c.channelName.equals(channelName)) {
				channelExist = true;
			}
		}

		// if it doesn't add it to the list
		if (!channelExist) {
			channels.add(new Channel(channelName));
			messageHistoryGroup.put(channelName, new ArrayList<ChatMessage>());
			userGroup.put("channel", new ArrayList<User>());
		}
	}

	public void setCurrentChannel(String channelName) {

		for (Channel c : channels) {
			if (c.channelName.equals(channelName)) {
				currentChannel = c;
			}
		}

		currentChannel.connected = ChannelState.CONNECTED;
	}

	public void recieveMessage(String messageRecieved, String sender,
			String channelName) {

		if (this.messageHistoryGroup.containsKey(channelName)) {

			List<ChatMessage> chatHistory = this.messageHistoryGroup
					.get(channelName);
			chatHistory
					.add(new ChatMessage(sender, messageRecieved, new Date()));

			ChatFragment.instance.refresh();
		}
	}

	// user grouped by channel
	public Map<String, List<User>> userGroup;

	// message history grouped by channel; 0th entry is the first message
	public Map<String, List<ChatMessage>> messageHistoryGroup;

	@Override
	public void onCreate() {

		instance = this;

		super.onCreate();

		messageHandler = new IRCHandler();
		myConnection = new IRCServiceConnection();

		channels = new ArrayList<Channel>();
		userGroup = new HashMap<String, List<User>>();
		messageHistoryGroup = new HashMap<String, List<ChatMessage>>();

		this.currentUser = null;
	}

	public void login(String nick, String ip) {

		Bundle param = new Bundle();
		param.putString("ip", ip);
		param.putString("nick", nick);

		Intent intent = new Intent(this, IRCService.class);
		intent.putExtras(param);

		startService(intent);
		bindService(intent, myConnection, Context.BIND_AUTO_CREATE);
	}

	public void joinChannel(Channel channel) {

		if (channel.connected == ChannelState.CONNECTED) {
			// if connected then simply switch view
			this.currentChannel = channel;
			IRCService.client.channel = channel.channelName;

			Main.instance.update();
			ChannelsFragment.instance.refresh();
			ChatFragment.instance.refresh();
			Main.instance.showView(1);

		} else if (channel.connected == ChannelState.AVAILABLE) {

			// otherwise wait for irc call back then switch view
			IRCService.client.setChannel(channel.channelName);
			channel.connected = ChannelState.CONNECTING;
			
			ChannelsFragment.instance.refresh();
		}
		// ignore when ChannelState.CONNECTING
	}

	public void sendMessage(String message) {

		List<ChatMessage> currentMessages = this.messageHistoryGroup
				.get(currentChannel.channelName);
		IRCService.client.sendMessage(message);
		currentMessages.add(new ChatMessage(currentUser.nick, message,
				new Date()));
		ChatFragment.instance.refresh();
	}

	public void logout() {

		// nullifies session data
		this.currentUser = null;
		this.currentChannel = null;

		this.channels.clear();
		this.userGroup.clear();
		this.messageHistoryGroup.clear();

		// close irc connection
		IRCService.client.disconnect();

		// unbind from service
		unbindService(myConnection);

		// stop service
		stopService(new Intent(this, IRCService.class));

	}
}

class IRCHandler extends Handler {

	public void handleMessage(Message message) {
		String msg = (String) message.obj;

		if (msg.equals("CONNECTED")) {

			Bundle b = message.getData();
			String nick = b.getString("nick");
			UTSirC.instance.currentUser = new User(nick, "");
			ConnectActivity.instance.notifyConnected();

		} else if (msg.equals("CHANNEL")) {

			// irc sends channel information 1 by 1
			Bundle b = message.getData();
			String channel = b.getString("channel");
			UTSirC.instance.addChannel(channel);
			ChannelsFragment.instance.refresh();

		} else if (msg.equals("JOINED")) {

			Bundle b = message.getData();
			String channel = b.getString("channel");
			UTSirC.instance.setCurrentChannel(channel);

			Main.instance.update();
			ChannelsFragment.instance.refresh();
			ChatFragment.instance.refresh();
			Main.instance.showView(1);

		} else if (msg.equals("RECIEVED")) {

			Bundle bundle = message.getData();
			// Log.d("messageHandler", bundle.getString("channel"));
			// Log.d("messageHandler", bundle.getString("hostname"));
			// Log.d("messageHandler", bundle.getString("login"));

			String sender = bundle.getString("sender");
			String messageRecieved = bundle.getString("message");
			String channel = bundle.getString("channel");

			UTSirC.instance.recieveMessage(messageRecieved, sender, channel);

		} else if (msg.equals("NICKINUSEEXCEPTION")
				|| msg.equals("IOEXCEPTION") || msg.equals("IRCEXCEPTION")) {
			ConnectActivity.instance.notifyError(msg);
		}
	}
}
